package yxy.apple.util;

import java.math.BigInteger;
import java.text.DecimalFormat;

public class NumberUtility {

	/**
	 * 百分比数字的小数点保留情况
	 * 
	 * @author HunterX
	 *
	 */
	public static enum PercentPrecision {
		Zero(0), One(1), Two(2), Three(3);

		private DecimalFormat formatter = null;

		PercentPrecision(int precision) {
			StringBuffer buffer = new StringBuffer();
			buffer.append("0");
			if (precision > 0) {
				buffer.append(".");
			}
			for (int i = 0; i < precision; i++) {
				buffer.append("0");
			}
			buffer.append("%");
			this.formatter = new DecimalFormat(buffer.toString());
		}
	}

	/**
	 * 小数数字的小数点保留情况
	 * 
	 * @author HunterX
	 *
	 */
	public static enum DecimalPrecision {
		Zero(0), One(1), Two(2), Three(3), Four(4), Five(5), Six(6), Seven(7), Eight(8), Nine(9), Ten(10), FixedOne(1, true), FixedTwo(2, true),
		FixedThree(3, true), FixedFour(4, true), FixedFive(5, true), FixedSix(6, true), FixedSeven(7, true), FixedEight(8, true), FixedNine(9, true),
		FixedTen(10, true);

		private DecimalFormat formatter = null;

		DecimalPrecision(int precision, boolean fixed) {
			StringBuffer buffer = new StringBuffer();
			buffer.append("#");
			if (precision > 0) {
				buffer.append(".");
			}
			for (int i = 0; i < precision; i++) {
				buffer.append(fixed ? "0" : "#");
			}
			this.formatter = new DecimalFormat(buffer.toString());
		}

		DecimalPrecision(int precision) {
			this(precision, false);
		}
	}

	public static String format(double value, PercentPrecision precision) {
		return precision.formatter.format(value);
	}

	public static String format(double value, DecimalPrecision precision) {
		return precision.formatter.format(value);
	}

	public static long parseLong(String string, long defaultValue) {
		long value = defaultValue;
		if (string != null) {
			try {
				value = Long.parseLong(string);
			} catch (NumberFormatException e) {
			}
		}
		return value;
	}

	public static int parseUnsignedInt(String string, int defaultValue) {
		try {
			return Integer.parseUnsignedInt(string, 16);
		} catch (NumberFormatException e) {
			return defaultValue;
		}
	}

	public static int parseInt(String string, int defaultValue) {
		try {
			return Integer.parseInt(string);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	public static int parseInt(String string, int radix, int defaultValue) {
		try {
			if (radix == 10) {
				return parseInt(string, defaultValue);
			} else {
				BigInteger bi = BigIntegerUtility.parse(string, radix);
				BigInteger max = BigInteger.TWO.pow(32);
				if (bi.compareTo(max) < 0) {
					return bi.intValue();
				} else {
					return defaultValue;
				}
			}
		} catch (Exception e) {
			return defaultValue;
		}
	}

	public static byte parseByte(String string, byte defaultValue) {
		try {
			return Byte.parseByte(string);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	public static short parseShort(String string, short defaultValue) {
		short value = defaultValue;
		if (string != null) {
			try {
				value = Short.parseShort(string);
			} catch (NumberFormatException e) {
			}
		}
		return value;
	}

	public static boolean parseBoolean(String string, boolean defaultValue) {
		boolean value = defaultValue;
		if (string != null) {
			try {
				value = Boolean.parseBoolean(string);
			} catch (NumberFormatException e) {
			}
		}
		return value;
	}

	/**
	 * TODO 暂时未做负数支持
	 * 
	 * @param string
	 * @param radix
	 * @param defaultValue
	 * @return
	 */
	public static long parseLong(String string, int radix, long defaultValue) {
		try {
			if (radix == 10) {
				return parseLong(string, defaultValue);
			} else {
				BigInteger bi = BigIntegerUtility.parse(string, radix);
				BigInteger max = BigInteger.TWO.pow(64);
				if (bi.compareTo(max) < 0) {
					return bi.longValue();
				} else {
					return defaultValue;
				}
			}
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 约等于
	 * 
	 * @param one
	 * @param another
	 * @param accuracy
	 * @return
	 */
	public static boolean isApproximate(double one, double another, int accuracy) {
		long oneL = (long) (one * Math.pow(10, accuracy) + 0.5);
		long twoL = (long) (another * Math.pow(10, accuracy) + 0.5);
		return oneL == twoL;
	}

	public static byte[] toBytes(int value) {
		byte[] bytes = new byte[4];
		bytes[0] = (byte) ((value & 0xFF000000) >> 24);
		bytes[1] = (byte) ((value & 0x00FF0000) >> 16);
		bytes[2] = (byte) ((value & 0x0000FF00) >> 8);
		bytes[3] = (byte) ((value & 0x000000FF) >> 0);
		return bytes;
	}

	public static String toString(long value, int radix) {
		return toString(BigInteger.valueOf(value), 64, radix);
	}

	public static String toString(int value, int radix) {

		return toString(BigInteger.valueOf(value), 32, radix);
	}

	private static String toString(BigInteger value, int bits, int radix) {
		if (radix < BigIntegerUtility.MinRadix || radix > BigIntegerUtility.MaxRadix) {
			throw new IllegalArgumentException();
		}
		if (value.signum() < 0) {
			BigInteger base = BigInteger.TWO.pow(bits);
			BigInteger v = base.add(value);
			return BigIntegerUtility.toString(v, radix);
		} else {
			return BigIntegerUtility.toString(value, radix);
		}
	}

	/**
	 * 等差数列求和
	 * 
	 * @param a1 首项值
	 * @param n  项目数
	 * @param d  公差
	 * @return 等差数列和
	 */
	public static int arithmeticSum(int a1, int n, int d) {
		if (n <= 0) {
			return 0;
		}
		return a1 * n + n * (n - 1) / 2 * d;
	}
}
